#ifndef INDEXADOHASHEXTENSIBLE_H_
#define INDEXADOHASHEXTENSIBLE_H_

#include <vector>

#include "Archivo.h"
#include "EstrategiaHash.h"
#include "includes.h"
#include "Indice.h"
#include "Directorio.h"

class Cuba;
class Clave;

namespace Toolkit
{

class IndiceHashExtensible : public Indice
{

public:

	IndiceHashExtensible(const unsigned long int tamanoComponente, const string &ruta, const string &nombre);

	/**
	 * Recuperar el hashing creado antes.
	 */
	IndiceHashExtensible(const string &ruta, const string &nombre);

	virtual ~IndiceHashExtensible();

	virtual bool eliminar(const Clave &clave);

	virtual void insertar(const Clave & clave, const unsigned long int &posicionBloque);

	virtual bool buscar(const Clave &clave, unsigned long int &posicionBloque) const;

	/**
	 * Dada una clave devuelve el numero del registro donde se debe encontrar. Para esto utiliza
	 * los ultimos bits del resultado de la funcionHash.
	 */
	unsigned long int crearDireccion(const Clave &clave, int cantidadBits = -1) const;

	/**
	* Dada una claveHasheada devuelve el numero del registro donde se debe encontrar. Para esto utiliza
	* los ultimos bits del resultado de la funcionHash.
	*/
	unsigned long int crearDireccion(const string &claveHasheada, int cantidadBits = -1) const;

private:

	/**
	 * Estrategia que encapsula el algoritmo de Hash.
	 */
	EstrategiaHash *estrategiaHash;

	Directorio *directorio;

	Archivo *almacenamientoCubas;

	unsigned long int tamanoComponente;

	/**
	 * Dada una clave y/o una direccion, devuelve la cuba
	 * donde deberia estar la clave buscada.
	 */
	Cuba* buscarCuba(const Clave &clave, long int direccionDirectorio = -1) const;

	/**
	 * Intenta combinar un cuba y hace la respectiva llamada a Contraer en caso de tener exito.
	 * Si el directorio se contrajo, se vuelve a llamar a IntentarCombinar recursivamente.
	 */
	void intentarCombinar(Cuba &cuba, long int &posicionCuba, const Clave &clave);

	/**
	 * Dada una cuba, devuelve por argumento el rango de posiciones que debe ocupar en el
	 * almacenamientoDirectorio, siendo COMIENZO la primer posicion direccionada a esta cuba,
	 * y FIN la primer direccion consecutiva que NO esta direccionada a la misma.
	 */
	void calcularRangoDirecciones(const Cuba &cuba, unsigned int &comienzo, unsigned int &fin) const;

	/** Agrega la cuba al almacenamiento de cubas, y agrega su direccion fisica en el directorio*/
	void agregarCuba(const Cuba &cuba, const unsigned int inicio, const unsigned int fin);

	/** Agrega la cuba al almacenamiento y devuelve su posicion relativa en el */
	unsigned long int almacenarCuba(const Cuba &cuba);

	/** Elimina la cuba del almacenamiento de cubas */
	void eliminarCuba(const long int &direccionDirectorio);

	/** Modifica en el almacenamiento la cuba objetivo*/
	void actualizarCubaEnAlmacenamiento(const Cuba &cuba, long int posicionDirectorio = -1);
};

}

#endif /* INDEXADOHASHEXTENSIBLE_H_ */
